home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / os2 / vsoup11.zip / newsrc.cc < prev    next >
C/C++ Source or Header  |  1996-09-02  |  16KB  |  756 lines

  1. //  $Id: newsrc.cc 1.10 1996/09/02 13:26:44 hardy Exp $
  2. //
  3. //  This progam/module was written by Hardy Griech based on ideas and
  4. //  pieces of code from Chin Huang (cthuang@io.org).  Bug reports should
  5. //  be submitted to rgriech@ibm.net.
  6. //
  7. //  This file is part of soup++ for OS/2.  Soup++ including this file
  8. //  is freeware.  There is no warranty of any kind implied.  The terms
  9. //  of the GNU Gernal Public Licence are valid for this piece of software.
  10. //
  11. //  rg110796:
  12. //  - introduction of a hash list because performance was real bad
  13. //  - grpFirst/grpNext now returning only subscribed groups
  14. //  - newsrc is written if there were any changes (onyl then!)
  15. //
  16.  
  17.  
  18. #include <assert.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22.  
  23. #include "mts.hh"
  24. #include "newsrc.hh"
  25. #include "util.hh"
  26.  
  27.  
  28.  
  29. TNewsrc::TNewsrc( void )
  30. {
  31.     int i;
  32.     
  33. #ifdef TRACE_ALL
  34.     printfT( "TNewsrc::TNewsrc()\n" );
  35. #endif
  36.     groups         = NULL;
  37.     filename       = xstrdup("");
  38.     cacheGroup     = NULL;
  39.     cacheGroupName = NULL;
  40.     addGroupP      = NULL;
  41.     fileRead       = 0;
  42.     for (i = 0;  i < hashSize;  ++i)
  43.     hashTab[i] = (pGroup)NULL;
  44. }   // TNewsrc::TNewsrc
  45.  
  46.  
  47.  
  48. TNewsrc::~TNewsrc()
  49. {
  50.     Range *rp1, *rp2;
  51.     pGroup gp1, gp2;
  52.     
  53. ////    delete filename;
  54.     gp1 = groups;
  55.     while (gp1 != NULL) {
  56.     rp1 = gp1->readList;
  57.     while (rp1 != NULL) {
  58.         rp2 = rp1->next;
  59. ////        delete rp1;
  60.         rp1 = rp2;
  61.     }
  62.     gp2 = gp1->next;
  63. ////    delete gp1->name;
  64. ////    delete gp1;
  65.     gp1 = gp2;
  66.     }
  67. }   // TNewsrc::~TNewsrc
  68.  
  69.  
  70.  
  71. TNewsrc::Range *TNewsrc::getReadList(FILE *nrcFile)
  72. //
  73. //  Read the article numbers from a .newsrc line.
  74. //
  75. {
  76.     static const char digits[] = "%[0123456789]";
  77.     Range *pLast, *rp, *head;
  78.     int lo, hi, c;
  79.     char buf[20];
  80.  
  81.     /* Initialize subscription list */
  82.     pLast = NULL;
  83.     head = NULL;
  84.  
  85.     /* Expect [ \n] */
  86.     c = fgetcT(nrcFile);
  87.  
  88.     while (c != '\n' && c != EOF) {
  89.     /* Expect number */
  90.     if (fscanfT(nrcFile, digits, buf) != 1)
  91.         break;
  92.     lo = atoi(buf);
  93.  
  94.     /* Get space for new list entry */
  95.     rp = new Range;
  96.     rp->next = NULL;
  97.  
  98.     /* Expect [-,\n] */
  99.     c = fgetcT(nrcFile);
  100.     if (c == '-') {
  101.         /* Is a range */
  102.         /* Expect number */
  103.         if (fscanfT(nrcFile, digits, buf) != 1)
  104.         break;
  105.         hi = atoi(buf);
  106.  
  107.         rp->lo = lo;
  108.         rp->hi = hi;
  109.  
  110.         /* Reverse them in case they're backwards */
  111.         if (hi < lo) {
  112.         rp->lo = hi;
  113.         rp->hi = lo;
  114.         }
  115.         if (rp->lo == 0)  //???
  116.         rp->lo = 1;
  117.  
  118.         /* Expect [,\n] */
  119.         c = fgetcT(nrcFile);
  120.     } else {
  121.         /* Not a range */
  122.         rp->lo = rp->hi = lo;
  123.     }
  124.     if (rp->lo == 0) {   //???
  125. ////        delete rp;
  126.         continue;
  127.     }
  128.  
  129.     /* Check if range overlaps last one */
  130.     if (pLast != NULL  &&  rp->lo <= pLast->hi + 1) {
  131.         /* Combine ranges */
  132.         if (rp->lo < pLast->lo)
  133.         pLast->lo = rp->lo;
  134.         if (rp->hi > pLast->hi)
  135.         pLast->hi = rp->hi;
  136.  
  137.         /* Free old (ehm new?) one */
  138. ////        delete rp;
  139.     } else {
  140.         /* No overlap, update pointers */
  141.         if (pLast == NULL) {
  142.         head = rp;
  143.         } else {
  144.         pLast->next = rp;
  145.         }
  146.         pLast = rp;
  147.     }
  148.     }
  149.  
  150.     return head;
  151. }   // TNewsrc::getReadList
  152.  
  153.  
  154.  
  155. int TNewsrc::readFile( const char *newsrcFile )
  156. //
  157. //  Read the .newsrc file.
  158. //  Return 0 on error (otherwise 1)
  159. //
  160. {
  161.     FILE *nrcFile;
  162.     char group_name[BUFSIZ], ch;
  163.  
  164. #ifdef TRACE_ALL
  165.     printfT("TNewsrc::readFile(%s)\n",newsrcFile);
  166. #endif
  167.     assert( !fileRead );
  168.  
  169.     /* Open it */
  170.     if ((nrcFile = fopenT(newsrcFile, "r")) == NULL) {
  171.     fprintfT(stderr, "Cannot open %s\n", newsrcFile);
  172.     return 0;
  173.     }
  174.     filename = xstrdup(newsrcFile);
  175.  
  176.     sema.Request();
  177.  
  178.     /* Read newsgroup entry */
  179.     while (fscanfT(nrcFile, "%[^:! \t\n]%*[ \t]", group_name) == 1) {
  180.     pGroup np;
  181.  
  182.     if (group_name[0] == '\0')
  183.         break;
  184.  
  185.     //
  186.     //  Allocate a new entry
  187.     //
  188.     np = (pGroup)grpAdd( group_name );
  189.     ch = fgetcT(nrcFile);
  190.     if (ch == '\n') {
  191.         /* The user didn't end the line with a colon. */
  192.         np->subscribed = 1;
  193.     } else {
  194.         /* Parse subscription list */
  195.         np->subscribed = (ch == ':');
  196.         np->readList = getReadList(nrcFile);
  197.     }
  198.     }
  199.  
  200.     fcloseT(nrcFile);
  201.     fileRead = 1;
  202.     fileChanged = 0;
  203.  
  204.     sema.Release();
  205.  
  206.     return 1;
  207. }   // TNewsrc::readFile
  208.  
  209.  
  210.  
  211. void TNewsrc::putReadList(FILE *fd, Range *head)
  212. //
  213. //  Write the article numbers for a .newsrc entry.
  214. //
  215. {
  216.     if (head == NULL)
  217.     fputcT('0',fd);
  218.     else {
  219.     while (head != NULL) {
  220.         if (head->lo == head->hi)
  221.         fprintfT(fd, "%ld", head->lo);
  222.         else
  223.         fprintfT(fd, "%ld-%ld", head->lo, head->hi);
  224.         head = head->next;
  225.         if (head != NULL)
  226.         fputcT(',', fd);
  227.     }
  228.     }
  229.     fputcT('\n', fd);
  230. }   // TNewsrc::putReadList
  231.  
  232.  
  233.  
  234. int TNewsrc::writeFile(void)
  235. //
  236. //  Rewrite the updated .newsrc file
  237. //
  238. {
  239.     char oldFile[FILENAME_MAX];
  240.     FILE *nrcFile;
  241.     pGroup np;
  242.  
  243. #ifdef TRACE_ALL
  244.     printfT( "TNewsrc::writeFile()\n" );
  245. #endif
  246.     if (filename[0] == '\0')
  247.     return 1;                        // successful (cause nothing to do)
  248.     if (groups == NULL  ||  !fileRead  ||  !fileChanged)
  249.     return 1;
  250.  
  251.     sema.Request();
  252.  
  253.     //
  254.     //  Back up old .newsrc file.
  255.     //
  256.     sprintfT(oldFile, "%s.old", filename);
  257.     remove(oldFile);
  258.     rename(filename, oldFile);
  259.  
  260.     if ((nrcFile = fopenT(filename, "w")) == NULL) {
  261.     fprintfT(stderr, "Cannot write %s\n", filename);
  262.     sema.Release();
  263.     return 0;
  264.     }
  265.  
  266.     for (np = groups; np != NULL; np = np->next) {
  267.     fputsT(np->name, nrcFile);
  268.     fputcT(np->subscribed ? ':' : '!', nrcFile);
  269.     fputcT(' ', nrcFile);
  270.     putReadList(nrcFile, np->readList);
  271.     }
  272.     fcloseT(nrcFile);
  273.     sema.Release();
  274.     return 1;
  275. }   // TNewsrc::writeFile
  276.  
  277.  
  278.  
  279. //--------------------------------------------------------------------------------
  280.  
  281.  
  282.  
  283. TNewsrc::pGroup TNewsrc::getGroupP( const char *groupName )
  284. //
  285. //  check, if groupName exists (return NULL, if not, otherwise pGroup)
  286. //  "cache" is updated
  287. //
  288. {
  289.     pGroup np;
  290.     pGroup res;
  291.  
  292. #ifdef TRACE_ALL
  293. //    printfT( "TNewsrc::getGroupP(%s)\n", groupName );
  294. #endif
  295.  
  296.     sema.Request();
  297.     if (cacheGroupName == NULL  ||  stricmp(groupName,cacheGroupName) != 0) {
  298.     int hasho;
  299.  
  300.     hasho = hashi(groupName,hashSize);
  301.     
  302.     for (np = hashTab[hasho];  np != NULL;  np = np->hashNext) {
  303.         if (stricmp(np->name, groupName) == 0) {
  304.         cacheGroupName = np->name;
  305.         cacheGroup     = np;
  306.         break;
  307.         }
  308.     }
  309.     if (np == NULL) {
  310.         cacheGroupName = NULL;
  311.         cacheGroup     = NULL;
  312.     }
  313.     }
  314.     res = cacheGroup;
  315.     sema.Release();
  316. #ifdef TRACE_ALL
  317. //    printfT( "TNewsrc::getGroupP(%s) = %p\n", groupName,cacheGroup );
  318. #endif
  319.     return res;
  320. }   // TNewsrc::getGroupP
  321.  
  322.  
  323.  
  324. void TNewsrc::grpFixReadList( const char *groupName, long groupLo, long groupHi )
  325. //
  326. //  Sanity fixes to the read article number list
  327. //
  328. {
  329.     pGroup np = getGroupP( groupName );
  330.     Range *rp1, *rp2;
  331.  
  332. #ifdef TRACE_ALL
  333.     printfT( "TNewsrc::grpFixReadList(%s,%ld,%ld) ",groupName,groupLo,groupHi );
  334.     putReadList( stdout, np->readList );
  335. #endif
  336.     assert( np != NULL );
  337.     sema.Request();
  338.  
  339.     //
  340.     //  If the highest read article is greater than the highest
  341.     //  available article, assume the group has been reset.
  342.     //
  343.     if (np->readList != NULL) {
  344.     for (rp1 = np->readList; rp1->next != NULL; rp1 = rp1->next)    // find end of list
  345.         ;
  346.     if (rp1->hi > groupHi) {
  347.         //
  348.         //  delete all of the list
  349.         //
  350.         rp1 = np->readList;
  351.         while (rp1 != NULL) {
  352.         rp2 = rp1->next;
  353. ////        delete rp1;
  354.         rp1 = rp2;
  355.         }
  356.         np->readList = NULL;
  357.     }
  358.     }
  359.  
  360.     //
  361.     //  eliminate ranges lower than the lowest available article
  362.     //  proceed from the beginning of the list...
  363.     //
  364.     rp1 = np->readList;
  365.     while (rp1 != NULL  &&  groupLo > rp1->hi) {
  366. #ifdef DEBUG_ALL
  367.     printfT( "ellower: \n" );
  368.     putReadList( stdout, np->readList );
  369. #endif
  370.     np->readList = rp1->next;
  371. ////    delete rp1;
  372.     rp1 = np->readList;
  373.     }
  374.  
  375.     //
  376.     //  All entries with a range below groupLo have